using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Linq;
using System.Linq.Expressions;

using EntModApp.EntServices;
using EntModApp.EntServices.Data;

namespace DemoApp.DataAccess 
{
  public partial class SecurableActionQueryableRepository : 
    DbContextQueryableRepository<DemoAppModelDbContext, SecurableAction>,
    IQueryableSecurableActionRepository
  {
    public SecurableActionQueryableRepository(DemoAppModelDbContext context)
      : this(context, false)
    {
    }

    public SecurableActionQueryableRepository()
      : this(new DemoAppModelDbContext(), true)
    {
    }

    protected SecurableActionQueryableRepository(DemoAppModelDbContext context, bool ownContext)
      : base(context, context.SecurableActions, ownContext)
    {
    }
  }

  public partial class SecurableActionDataRepository : 
    DbContextDataRepository<DemoAppModelDbContext, SecurableAction, SecurableActionLoadSettings>,
    ISecurableActionRepository
  {
    public SecurableActionDataRepository(DemoAppModelDbContext context)
      : this(context, false)
    {
    }

    public SecurableActionDataRepository()
      : this(new DemoAppModelDbContext(), true)
    {
    }

    protected SecurableActionDataRepository(DemoAppModelDbContext context, bool ownContext)
      : base(context, context.SecurableActions, ownContext)
    {
    }

    public override IEnumerable<SecurableAction> RetrieveAll(out int total, bool retrieveTotal)
    {
      var query = new SecurableActionLoadSettings
      {
        Paging = new PagingSettings { ComputeTotal = retrieveTotal }
      };
      return Retrieve(query, out total);
    }

    public override IEnumerable<SecurableAction> Retrieve(SecurableActionLoadSettings query, out int total)
    {
      var dbQuery = DataSet.ApplySecurableActionLoadSettings(query, out total);
      return dbQuery.ToList();
    }

    public override int Count()
    {
      return DataSet.Count();
    }

    public override int Count(SecurableActionLoadSettings query)
    {
      var dbQuery = DataSet.ApplySecurableActionFilterExpression(query.Filter);
      return dbQuery.Count();
    }
  }

  public static class SecurableActionQueryableRepositoryExtensions
  {
    public static IQueryable<SecurableAction> ApplySecurableActionLoadSettings(this IQueryable<SecurableAction> query, SecurableActionLoadSettings loadSettings, out int total)
    {
      if (loadSettings == null)
        loadSettings = new SecurableActionLoadSettings();

      query = query.ApplySecurableActionInclusionSettings(loadSettings.Inclusion);

      query = query.ApplySecurableActionFilterExpression(loadSettings.Filter);

      query = query.ApplySecurableActionSortingSettings(loadSettings.Sorting);

      query = query.ApplyPagingSettings(loadSettings.Paging, out total);

      query = query.ApplySecurableActionSelectionSettings(loadSettings.Selection);

      return query;
    }

    public static IEnumerable<string> GetDirectSecurableActionInclusionPaths(this SecurableActionInclusionSettings inclusionSettings)
    {
      if (inclusionSettings.IncludeRoles) yield return "Roles";

      yield break;
    }

    public static IEnumerable<string> GetSecurableActionInclusionPaths(this SecurableActionInclusionSettings inclusionSettings)
    {
      foreach (var path in inclusionSettings.GetDirectSecurableActionInclusionPaths())
        yield return path;

      if (inclusionSettings.IncludeRoles)
        foreach (var referencePath in inclusionSettings.IncludedRolesSettings.Inclusion.GetRoleInclusionPaths())
          yield return "Roles." + referencePath;

      yield break;
    }

    public static IQueryable<SecurableAction> ApplySecurableActionInclusionSettings(this IQueryable<SecurableAction> query, SecurableActionInclusionSettings inclusionSettings)
    {
      foreach (var path in inclusionSettings.GetSecurableActionInclusionPaths())
        query = query.Include(path);

      return query;
    }

    public static IQueryable<SecurableAction> ApplySecurableActionFilterExpression(this IQueryable<SecurableAction> query, SecurableActionFilterExpression filterExpression)
    {
      if (filterExpression.ByKey != null)
        query = query.Where(o => o.SecurableActionId == filterExpression.ByKey.SecurableActionId);

      var parameter = Expression.Parameter(typeof(SecurableAction), "e");
      if (filterExpression.SecurableActionIdFilter != null)
        query = query.Where(filterExpression.SecurableActionIdFilter.CreateExpressionBody<SecurableAction, Guid>(SecurableActionPropertyNames.SecurableActionId, parameter).ToLambda<SecurableAction>(parameter));
      if (filterExpression.NameFilter != null)
        query = query.Where(filterExpression.NameFilter.CreateExpressionBody<SecurableAction, string>(SecurableActionPropertyNames.Name, parameter).ToLambda<SecurableAction>(parameter));

      if (filterExpression.Skip.HasValue)
        query = query.Skip(filterExpression.Skip.Value);
      if (filterExpression.Take.HasValue)
        query = query.Take(filterExpression.Take.Value);

      return query;
    }

    public static IQueryable<SecurableAction> ApplySecurableActionSortingSettings(this IQueryable<SecurableAction> query, SecurableActionSortingSettings sortingSettings)
    {
      return query;
    }

    public static IQueryable<SecurableAction> ApplySecurableActionSelectionSettings(this IQueryable<SecurableAction> query, SecurableActionSelectionSettings selectionSettings)
    {
      return query;
    }

  }
}
